﻿Imports System.Runtime.CompilerServices
Imports System.Linq
Imports System.Text.RegularExpressions

Public Module WinformsExtensions

    <Extension()> _
    Public Sub Alert(ByVal ctrl As Form, ByVal strMessage As String)
        MessageBox.Show(strMessage, ctrl.Text & " Informa:")
    End Sub
    <Extension()> _
    Public Function Confirma(ByVal ctrl As Form, ByVal strMessage As String) As Boolean
        Return MessageBox.Show(strMessage, ctrl.Text & " Confirma:", MessageBoxButtons.YesNo) = DialogResult.Yes

    End Function

    <Extension()> _
    Public Sub AlertException(ByVal ctrl As Form, ByVal excepcion As Exception)
        MessageBox.Show(excepcion.Message, ctrl.Text & " Informa:", MessageBoxButtons.OK, MessageBoxIcon.Error)
    End Sub

    <Extension()> _
    Public Function EsNumero(ByVal ctrl As TextBox) As Boolean
        'Si está vacio
        If String.IsNullOrEmpty(ctrl.Text) Then
            Return False
        End If

        'si se le hace un trim y está vacío
        If String.IsNullOrEmpty(ctrl.Text.Trim()) Then
            Return False
        End If

        'si es número
        If IsNumeric(ctrl.Text) Then
            Return True
        End If

        'si no es ninguna de las opciones
        'retorna falso
        Return False


    End Function

    <Extension()> _
    Function IsEmail(ByVal ctrl As TextBox) As Boolean
        If ctrl.Text.IsNothing() Then
            Return False
        End If
        Static emailExpression As New Regex("^[_a-z0-9-]+(.[a-z0-9-]+)@[a-z0-9-]+(.[a-z0-9-]+)*(.[a-z]{2,4})$")
        ctrl.Text = ctrl.Text.Trim()
        Return emailExpression.IsMatch(ctrl.Text)
    End Function

    <Extension()> _
    Public Function EsNumeroEntero(ByVal ctrl As TextBox) As Boolean
        If EsNumero(ctrl) Then
            Dim num As Integer
            If Not Integer.TryParse(ctrl.Text.Trim(), num) Then
                Return False
            Else
                Return True
            End If

        Else
            Return False
        End If
    End Function

    <Extension()> _
    Public Function EsFechaValida(ByVal ctrl As TextBox) As Boolean
        Dim dt As Date
        If Not Date.TryParse(ctrl.Text.Trim(), dt) Then
            Return False
        Else
            Return True
        End If
    End Function
    <Extension()> _
    Public Function EsNumeroMayorQueCero(ByVal crl As TextBox) As Boolean
        If Not EsNumero(crl) Then
            Return False
        Else
            Return Val(crl.Text) > 0
        End If
    End Function
    <Extension()> _
    Public Function NoEsVacio(ByVal crl As TextBox) As Boolean
        Return Not String.IsNullOrEmpty(crl.Text) AndAlso Not String.IsNullOrEmpty(crl.Text.Trim())
    End Function




    <Extension()> _
    Public Sub selectAll(ByVal lstb As CheckedListBox)
        If Not lstb.Items Is Nothing Then
            For i = 0 To lstb.Items.Count - 1
                lstb.SetItemChecked(i, True)
            Next
        End If
    End Sub

    Private Function getControlValue(ByVal ctl As Control) As Object

        Dim t As Type = ctl.GetType()

        Select Case True
            Case TypeOf ctl Is Windows.Forms.TextBox
                Return ctl.Text.Trim()

            Case TypeOf ctl Is Windows.Forms.ComboBox
                Return CType(ctl, Windows.Forms.ComboBox).SelectedValue

            Case TypeOf ctl Is Windows.Forms.CheckBox
                Return CType(ctl, CheckBox).Checked

            Case TypeOf ctl Is TrackBar
                Return CType(ctl, TrackBar).Value

            Case TypeOf ctl Is RichTextBox
                Return CType(ctl, RichTextBox).Text.Trim()

            Case TypeOf ctl Is DateTimePicker
                Return CType(ctl, DateTimePicker).Value

            Case Else

                Throw New ApplicationException("No se puede mapear el control " + ctl.GetType().Name)
        End Select

    End Function

    Public Sub setComboDefaultValue(ByRef cmb As ComboBox, value As Object)
        If cmb.Items IsNot Nothing AndAlso cmb.Items.Count > 0 Then
            For i As Integer = 0 To cmb.Items.Count - 1
                If CStr(cmb.Items(i).DataValueField) = CStr(value) Then
                    cmb.SelectedIndex = i
                    Exit For
                End If
            Next
        End If
    End Sub

    Public Sub setControlValue(ByVal ctl As Control, ByVal value As Object)

        Try
            Dim t As Type = ctl.GetType()

            Select Case True
                Case TypeOf ctl Is Windows.Forms.TextBox
                    ctl.Text = value
                Case TypeOf ctl Is Windows.Forms.ComboBox
                    Dim cmb = CType(ctl, Windows.Forms.ComboBox)
                    If cmb.Items IsNot Nothing AndAlso cmb.Items.Count > 0 _
                       AndAlso cmb.Items(0).GetType().GetProperties().Where(Function(x) x.Name.Equals("DataValueField", StringComparison.InvariantCultureIgnoreCase)).Any() Then
                        For i As Integer = 0 To cmb.Items.Count
                            If cmb.Items(i).DataValueField IsNot Nothing _
                                AndAlso cmb.Items(i).DataValueField.ToString().Equals(value.ToString(), StringComparison.InvariantCultureIgnoreCase) Then
                                cmb.SelectedIndex = i
                                Exit For
                            End If

                        Next
                    Else
                        cmb.SelectedValue = value
                    End If





                Case TypeOf ctl Is Windows.Forms.CheckBox
                    CType(ctl, CheckBox).Checked = CBool(CStr(value).Trim())
                Case TypeOf ctl Is TrackBar
                    CType(ctl, TrackBar).Value = value
                Case TypeOf ctl Is RichTextBox
                    ctl.Text = value
                Case TypeOf ctl Is Windows.Forms.DateTimePicker
                    CType(ctl, DateTimePicker).Value = value

                Case Else
                    Throw New ApplicationException("no se encontro el mapeo para: " + ctl.GetType().Name)
            End Select
        Catch ex As Exception
            Throw ex
        End Try

    End Sub
    <Extension()> _
    Public Sub MapFromObjectImplicit(ByVal ctl As Windows.Forms.Form, ByRef ObjectToMap As Object)
        MapFromObject(ctl, ObjectToMap)

    End Sub

    <Extension()> _
    Public Sub MapFromObject(ByRef ctl As Windows.Forms.Form, ByRef ObjectToMap As Object)
        'Dim ctls = ctl.GetSelfAndChildrenRecursive().Distinct()
        For Each prop In ObjectToMap.GetType().GetProperties().Where(Function(p) p.CanRead)
            Dim propName = prop.Name
            Dim cs = FindControlByName(ctl, propName)
            'Dim cs = ctls.Where(Function(x) x.Name.Equals(propName, StringComparison.CurrentCultureIgnoreCase))
            If cs.Any() Then
                Dim ctl1 = cs.FirstOrDefault()
                setControlValue(ctl1, prop.GetValue(ObjectToMap, Nothing))
            End If
        Next

    End Sub

    <Extension()> _
    Public Sub MapFromObjectControl(ByRef ctl As Control, ByRef ObjectToMap As Object)
        'Dim ctls = ctl.GetSelfAndChildrenRecursive().Distinct()
        For Each prop In ObjectToMap.GetType().GetProperties().Where(Function(p) p.CanRead)
            Dim propName = prop.Name
            Dim cs = FindControlByName(ctl, propName)
            'Dim cs = ctls.Where(Function(x) x.Name.Equals(propName, StringComparison.CurrentCultureIgnoreCase))
            If cs.Any() Then
                Dim ctl1 = cs.FirstOrDefault()
                setControlValue(ctl1, prop.GetValue(ObjectToMap, Nothing))
            End If
        Next

    End Sub


    <Extension()> _
    Public Sub MapToObject(ByRef ctl As Windows.Forms.Form, ByRef ObjectToMap As Object)
        'Dim ctls = ctl.GetSelfAndChildrenRecursive()
        For Each prop In ObjectToMap.GetType().GetProperties().Where(Function(p) p.CanWrite)
            Dim propName = prop.Name
            Dim cs = FindControlByName(ctl, propName)
            ' Dim cs = ctls.Where(Function(x) x.Name.Equals(propName, StringComparison.CurrentCultureIgnoreCase))
            If cs.Any() Then
                ReflectionHelper.SetEntityValue(ObjectToMap, propName, getControlValue(cs.FirstOrDefault()))
            End If
        Next

    End Sub
    <Extension()> _
    Public Sub MapToObjectImplicit(ByVal ctl As Windows.Forms.Form, ByRef ObjectToMap As Object)
        MapToObject(ctl, ObjectToMap)

    End Sub

    <Extension()> _
    Public Function FindControlByName(ByVal control As Control, ByVal ControlName As String) As IEnumerable(Of Control)
        Dim controls = control.Controls.Cast(Of Control)()

        Return controls.SelectMany(Function(ctrl) FindControlByName(ctrl, ControlName)).Concat(controls). _
        Where(Function(x) x.Name.Equals(ControlName, StringComparison.InvariantCultureIgnoreCase))


        '.Concat(controls).Where(Function(c) c.[GetType]() = type)
    End Function

    <Extension()> _
    Public Function GetSelfAndChildrenRecursive(ByVal parent As Control) As IEnumerable(Of Control)
        Dim controls As New List(Of Control)()

        For Each child As Control In parent.Controls
            controls.AddRange(GetSelfAndChildrenRecursive(child))
        Next

        controls.Add(parent)

        Return controls
    End Function

End Module
